package com.example.rssreader.service.impl;

import com.example.rssreader.entity.Article;
import com.example.rssreader.entity.RssFeed;
import com.example.rssreader.mapper.ArticleMapper;
import com.example.rssreader.mapper.RssFeedMapper;
import com.example.rssreader.service.RssParserService;
import com.rometools.rome.feed.synd.SyndEntry;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

/**
 * RSS解析服务实现类
 * 实现RSS源解析和文章抓取相关的业务逻辑
 * 
 * @author RSS Reader Team
 * @version 1.0.0
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RssParserServiceImpl implements RssParserService {

    private final ArticleMapper articleMapper;
    private final RssFeedMapper rssFeedMapper;

    /**
     * RSS请求超时时间（毫秒）
     */
    @Value("${rss.request.timeout:10000}")
    private Integer requestTimeout;

    /**
     * 每个RSS源最大抓取文章数量
     */
    @Value("${rss.max-articles:50}")
    private Integer maxArticles;

    /**
     * HTML标签清理正则表达式
     */
    private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<[^>]+>");

    /**
     * 解析RSS源信息
     * 从RSS URL获取基本信息（标题、描述等）
     * 
     * @param url RSS源URL
     * @return RSS源实体，包含解析出的基本信息
     * @throws RuntimeException 当URL无效或解析失败时抛出异常
     */
    @Override
    public RssFeed parseFeedInfo(String url) {
        log.info("开始解析RSS源信息，URL: {}", url);
        
        try {
            SyndFeed syndFeed = fetchSyndFeed(url);
            
            RssFeed rssFeed = new RssFeed();
            rssFeed.setUrl(url);
            rssFeed.setTitle(StringUtils.hasText(syndFeed.getTitle()) ? 
                    syndFeed.getTitle() : "未知RSS源");
            rssFeed.setDescription(StringUtils.hasText(syndFeed.getDescription()) ? 
                    syndFeed.getDescription() : "暂无描述");
            rssFeed.setLastUpdated(LocalDateTime.now().toString());

            log.info("RSS源信息解析成功，标题: {}", rssFeed.getTitle());
            return rssFeed;
            
        } catch (Exception e) {
            log.error("解析RSS源信息失败，URL: {}, 错误: {}", url, e.getMessage(), e);
            throw new RuntimeException("解析RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 解析RSS源的文章列表
     * 从RSS URL获取最新的文章列表
     * 
     * @param feed RSS源实体
     * @return 文章列表
     * @throws RuntimeException 当解析失败时抛出异常
     */
    @Override
    public List<Article> parseArticles(RssFeed feed) {
        log.info("开始解析RSS源文章，RSS源ID: {}, URL: {}", feed.getId(), feed.getUrl());
        
        try {
            SyndFeed syndFeed = fetchSyndFeed(feed.getUrl());
            List<Article> articles = new ArrayList<>();
            
            List<SyndEntry> entries = syndFeed.getEntries();
            int processedCount = 0;
            
            for (SyndEntry entry : entries) {
                if (processedCount >= maxArticles) {
                    log.debug("已达到最大文章数量限制: {}", maxArticles);
                    break;
                }
                
                try {
                    Article article = parseEntry(entry, feed.getId());
                    if (article != null) {
                        articles.add(article);
                        processedCount++;
                    }
                } catch (Exception e) {
                    log.warn("解析单个文章失败，跳过该文章: {}", e.getMessage());
                }
            }
            
            log.info("RSS源文章解析完成，RSS源ID: {}, 解析文章数量: {}", feed.getId(), articles.size());
            return articles;
            
        } catch (Exception e) {
            log.error("解析RSS源文章失败，RSS源ID: {}, URL: {}, 错误: {}", 
                    feed.getId(), feed.getUrl(), e.getMessage(), e);
            throw new RuntimeException("解析RSS源文章失败: " + e.getMessage());
        }
    }

    /**
     * 验证RSS URL是否有效
     * 检查URL是否可访问且为有效的RSS格式
     * 
     * @param url RSS源URL
     * @return true-有效，false-无效
     */
    @Override
    public boolean validateRssUrl(String url) {
        log.debug("验证RSS URL: {}", url);
        
        try {
            fetchSyndFeed(url);
            return true;
        } catch (Exception e) {
            log.debug("RSS URL验证失败: {}, 错误: {}", url, e.getMessage());
            return false;
        }
    }

    /**
     * 获取RSS源的最新更新时间
     * 从RSS源中解析最后更新时间
     * 
     * @param url RSS源URL
     * @return 最新更新时间字符串，解析失败时返回null
     */
    @Override
    public String getLastBuildDate(String url) {
        log.debug("获取RSS源最新更新时间，URL: {}", url);
        
        try {
            SyndFeed syndFeed = fetchSyndFeed(url);
            Date publishedDate = syndFeed.getPublishedDate();
            
            if (publishedDate != null) {
                return publishedDate.toString();
            }
            
            return null;
            
        } catch (Exception e) {
            log.debug("获取RSS源更新时间失败，URL: {}, 错误: {}", url, e.getMessage());
            return null;
        }
    }

    /**
     * 测试RSS源连接
     * 检查RSS源是否可正常访问
     * 
     * @param url RSS源URL
     * @return 连接测试结果信息
     */
    @Override
    public String testConnection(String url) {
        log.debug("测试RSS源连接，URL: {}", url);
        
        try {
            long startTime = System.currentTimeMillis();
            SyndFeed syndFeed = fetchSyndFeed(url);
            long endTime = System.currentTimeMillis();
            
            String result = String.format("连接成功！RSS源标题: %s，响应时间: %d ms，文章数量: %d",
                    syndFeed.getTitle(),
                    endTime - startTime,
                    syndFeed.getEntries().size());
            
            log.debug("RSS源连接测试成功: {}", result);
            return result;
            
        } catch (Exception e) {
            String errorMsg = "连接失败: " + e.getMessage();
            log.debug("RSS源连接测试失败，URL: {}, 错误: {}", url, e.getMessage());
            return errorMsg;
        }
    }

    /**
     * 解析单个RSS条目为文章实体
     * 内部方法，用于将RSS条目转换为Article对象
     * 
     * @param entry  RSS条目
     * @param feedId RSS源ID
     * @return 文章实体
     */
    @Override
    public Article parseEntry(Object entry, Long feedId) {
        if (!(entry instanceof SyndEntry)) {
            log.warn("无效的RSS条目类型");
            return null;
        }
        
        SyndEntry syndEntry = (SyndEntry) entry;
        
        try {
            Article article = new Article();
            article.setFeedId(feedId);
            
            // 设置标题
            article.setTitle(StringUtils.hasText(syndEntry.getTitle()) ? 
                    syndEntry.getTitle() : "无标题");
            
            // 设置链接
            article.setLink(StringUtils.hasText(syndEntry.getLink()) ? 
                    syndEntry.getLink() : "");
            
            // 设置GUID
            String guid = syndEntry.getUri();
            if (!StringUtils.hasText(guid)) {
                guid = syndEntry.getLink();
            }
            if (!StringUtils.hasText(guid)) {
                guid = syndEntry.getTitle() + "_" + System.currentTimeMillis();
            }
            article.setGuid(guid);
            
            // 设置描述
            if (syndEntry.getDescription() != null) {
                String description = syndEntry.getDescription().getValue();
                article.setDescription(extractSummary(cleanHtmlContent(description), 500));
            }
            
            // 设置内容
            if (syndEntry.getContents() != null && !syndEntry.getContents().isEmpty()) {
                String content = syndEntry.getContents().get(0).getValue();
                article.setContent(content);
            } else if (syndEntry.getDescription() != null) {
                article.setContent(syndEntry.getDescription().getValue());
            }
            
            // 设置作者
            article.setAuthor(StringUtils.hasText(syndEntry.getAuthor()) ? 
                    syndEntry.getAuthor() : "未知作者");
            
            // 设置发布时间
            Date publishedDate = syndEntry.getPublishedDate();
            if (publishedDate != null) {
                article.setPublishedAt(publishedDate.toInstant()
                        .atZone(ZoneId.systemDefault())
                        .toLocalDateTime().toString());
            } else {
                article.setPublishedAt(LocalDateTime.now().toString());
            }
            
            // 设置为未读
            article.setIsRead(false);
            
            return article;
            
        } catch (Exception e) {
            log.warn("解析RSS条目失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 清理HTML标签
     * 从文章内容中移除HTML标签，保留纯文本
     * 
     * @param htmlContent HTML内容
     * @return 纯文本内容
     */
    @Override
    public String cleanHtmlContent(String htmlContent) {
        if (!StringUtils.hasText(htmlContent)) {
            return "";
        }
        
        try {
            // 移除HTML标签
            String cleanText = HTML_TAG_PATTERN.matcher(htmlContent).replaceAll("");
            
            // 解码HTML实体
            cleanText = cleanText.replace("&nbsp;", " ")
                    .replace("&lt;", "<")
                    .replace("&gt;", ">")
                    .replace("&amp;", "&")
                    .replace("&quot;", "\"")
                    .replace("&#39;", "'");
            
            // 清理多余的空白字符
            cleanText = cleanText.replaceAll("\\s+", " ").trim();
            
            return cleanText;
            
        } catch (Exception e) {
            log.warn("清理HTML内容失败: {}", e.getMessage());
            return htmlContent;
        }
    }

    /**
     * 截取文章摘要
     * 从文章内容中提取指定长度的摘要
     * 
     * @param content 文章内容
     * @param maxLength 最大长度
     * @return 文章摘要
     */
    @Override
    public String extractSummary(String content, int maxLength) {
        if (!StringUtils.hasText(content)) {
            return "";
        }
        
        try {
            String cleanContent = cleanHtmlContent(content);
            
            if (cleanContent.length() <= maxLength) {
                return cleanContent;
            }
            
            // 截取指定长度，并在最后添加省略号
            String summary = cleanContent.substring(0, maxLength);
            
            // 尝试在最后一个完整单词处截断
            int lastSpaceIndex = summary.lastIndexOf(' ');
            if (lastSpaceIndex > maxLength * 0.8) {
                summary = summary.substring(0, lastSpaceIndex);
            }
            
            return summary + "...";
            
        } catch (Exception e) {
            log.warn("提取文章摘要失败: {}", e.getMessage());
            return content.length() > maxLength ? 
                    content.substring(0, maxLength) + "..." : content;
        }
    }

    /**
     * 批量解析多个RSS源
     * 用于定时同步任务
     * 
     * @param feeds RSS源列表
     * @return 解析结果统计信息
     */
    @Override
    public String batchParseFeeds(List<RssFeed> feeds) {
        log.info("开始批量解析RSS源，数量: {}", feeds.size());
        
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        AtomicInteger newArticleCount = new AtomicInteger(0);
        
        for (RssFeed feed : feeds) {
            try {
                List<Article> articles = parseArticles(feed);
                int newArticles = 0;
                
                for (Article article : articles) {
                    // 检查文章是否已存在
                    Article existingArticle = articleMapper.selectByGuid(article.getGuid(), feed.getId());
                    if (existingArticle == null) {
                        articleMapper.insert(article);
                        newArticles++;
                    }
                }
                
                // 更新RSS源的最后更新时间
                feed.setLastUpdated(LocalDateTime.now().toString());
                rssFeedMapper.updateById(feed);
                
                newArticleCount.addAndGet(newArticles);
                successCount.incrementAndGet();
                
                log.debug("RSS源同步成功，ID: {}, 新增文章: {}", feed.getId(), newArticles);
                
            } catch (Exception e) {
                failureCount.incrementAndGet();
                log.warn("RSS源同步失败，ID: {}, 错误: {}", feed.getId(), e.getMessage());
            }
        }
        
        String result = String.format("批量同步完成，成功: %d，失败: %d，新增文章: %d",
                successCount.get(), failureCount.get(), newArticleCount.get());
        
        log.info(result);
        return result;
    }

    /**
     * 获取SyndFeed对象
     * 内部方法，用于从URL获取RSS源数据
     * 
     * @param url RSS源URL
     * @return SyndFeed对象
     * @throws Exception 当获取失败时抛出异常
     */
    private SyndFeed fetchSyndFeed(String url) throws Exception {
        log.debug("开始获取RSS源数据，URL: {}", url);
        
        HttpURLConnection connection = null;
        InputStream inputStream = null;
        try {
            URL rssUrl = new URL(url);
            connection = (HttpURLConnection) rssUrl.openConnection();
            
            // 必须在连接之前设置所有请求属性
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(requestTimeout);
            connection.setReadTimeout(requestTimeout);
            connection.setRequestProperty("User-Agent", 
                    "RSS Reader Bot 1.0 (Compatible with RSS/Atom feeds)");
            connection.setRequestProperty("Accept", 
                    "application/rss+xml, application/atom+xml, application/xml, text/xml");
            connection.setRequestProperty("Cache-Control", "no-cache");
            
            // 手动连接
            connection.connect();
            
            // 检查响应码
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new IOException("HTTP响应码: " + responseCode);
            }
            
            // 获取输入流
            inputStream = connection.getInputStream();
            
            // 解析RSS源
            SyndFeedInput input = new SyndFeedInput();
            SyndFeed syndFeed = input.build(new XmlReader(inputStream));
            
            log.debug("RSS源数据获取成功，标题: {}, 文章数量: {}", 
                    syndFeed.getTitle(), syndFeed.getEntries().size());
            
            return syndFeed;
            
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.warn("关闭输入流失败: {}", e.getMessage());
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}